# -*- coding: utf-8 -*-
import datetime

from utils.utils import *

CATEGORY_CUTOFF = 0.6

VERIFY_MAP = {
    '-1': '普通用户',
    '0': '名人',
    '1': '政府',
    '2': '企业',
    '3': '媒体',
    '4': '校园',
    '5': '网站',
    '6': '应用',
    '7': '团体（机构）',
    '8': '待审企业',
    '200': '初级达人',
    '220': '中高级达人',
    '400': '已故V用户'
}

REV_VERIFY_MAP = {v: int(k) for k, v in VERIFY_MAP.items()}

CONTENT_TYPE_MAP = {
    '1': '文本',
    '2': '视频',
    '3': '图片'
}

REV_CONTENT_TYPE_MAP = {v: k for k, v in CONTENT_TYPE_MAP.items()}

MIN_SCORE = 0.4

HL_PRE_TAG = ['<span class="keyword">']
HL_POST_TAG = ['</span>']


def decode_verify(code):
    return VERIFY_MAP.get(str(code), None)


def encode_verify(text):
    return REV_VERIFY_MAP.get(text, None)


def decode_content_type(code):
    return CONTENT_TYPE_MAP.get(str(code), None)


def encode_content_type(text):
    return REV_CONTENT_TYPE_MAP.get(text, None)


# ['user_id', 'nick_name', 'avatar', 'user_type', 'gender', 'verified_type',
#                 'verified_reason', 'description', 'fans', 'posts', 'crawler_timestamp',
#                 'category', 'category_weight', 'content_type', 'content_type_weight',
#                 'keywords', 'keywords_weight', 'keywords_agg_date','sum_retweets',
#                 'avg_retweets','max_retweets','sum_comments','avg_comments','max_comments',
# 				'sum_likes','avg_likes','max_likes','sum_engagement','avg_engagement',
#                 'max_engagement','score']


def extract_user_from_source(source_):
    source_ = dict(source_)
    verify = source_.get('verified_type', None)
    decode_verify(verify)

    return {
        'user_id': source_['user_id'],
        'user_name': source_.get('nick_name', ''),
        'verify': verify,
        "location": source_.get('location', ''),
        'user_type': source_.get('user_type', ''),
        'verified_reason': source_.get('verified_reason', ''),
        'user_info': source_.get('description', ''),
        'categories': [category_smzdm_2_decode(c) for c in source_['categories']],
        'keywords': source_['keywords'][0:10],
        'gender': source_['gender'],
        'fans': source_['fans'],
        'posts': source_['posts'],
        'avatar': source_['avatar'],
        'score': source_['score'],
        'avg_likes': source_.get('avg_likes', 0),
        'avg_retweets': source_.get('avg_retweets', 0),
        'avg_comments': source_.get('avg_comments', 0),

        'min_likes': source_.get('min_likes', 0),
        'min_retweets': source_.get('min_retweets', 0),
        'min_comments': source_.get('min_comments', 0),

        'min_engagement': source_.get('min_engagement', 0),

        'verified_type': source_.get('verified_type'),
        'avg_engagement': source_.get('avg_engagement', 0),
        'engagement_ratio': source_.get('avg_engagement', 0) / (source_.get('fans', 0) + 0.1),
    }


def extract_img(h):
    if h[0:4] == 'http':
        return h
    else:
        return 'http://wx3.sinaimg.cn/mw690/' + h


def extract_post_from_source(source_):
    source_ = dict(source_)
    weibo_text = source_.get('weibo_text', '')
    r_weibo_text = source_.get('r_weibo_text', '')
    summary = weibo_text
    if r_weibo_text:
        summary += '//' + r_weibo_text

    return {
        'user_id': source_.get('user_id'),
        'weibo_id': source_.get('weibo_id'),
        'user_name': source_.get('nick_name'),
        'user_type': source_.get('user_type'),
        'url': source_.get('url'),
        'avatar': source_.get('avatar'),
        'summary': summary,
        'retweets': source_.get('retweets', 0),
        'is_retweet': source_.get('is_retweet'),
        'comments': source_.get('comments', 0),
        'likes': source_.get('likes', 0),
        'keywords': source_.get('keywords', []),
        'sum_engagement': source_.get('sum_engagement', 0),
        'device': source_.get('device', ''),
        'sentiment': source_.get('full_sentiment_category', ''),
        'sentiment_prob': source_.get('sentiment_category_weight', ''),
        'publish_timestamp': source_.get('publish_timestamp'),
        'pictures': [extract_img(i) for i in source_.get('pictures', []) if 30 < len(i) < 70 and ('<' not in i)],
        'video_names': source_.get('video_names', []),
        'video_links': source_.get('video_links', []),
        'topics': source_.get('topics')

    }


def filter_festivals(must_clause, festival_keywords):
    clause = []
    must_clause.append({
        'bool': {'should': clause}
    })
    for fk in festival_keywords:
        q = {
            'match_phrase': {
                "weibo_text": {
                    'query': fk,
                    'slop': 1,
                },
            }}
        clause.append(q)

    for fk in festival_keywords:
        q = {
            'match_phrase': {
                "r_weibo_text": {
                    'query': fk,
                    'slop': 1,
                },
            }}
        clause.append(q)

    q_keywords = {
        'multi_match': {
            'analyzer': 'whitespace',
            'query': ' '.join(festival_keywords),
            'fields': ['keywords', 'seg_weibo_text', 'seg_r_weibo_text'],
            # 'minimum_should_match': ""
        }
    }
    clause.append(q_keywords)
    return must_clause


def add_filter_clause_search(filter_clause, keywords):
    clause = []
    filter_clause.append({
        'bool': {
            'should': clause,
            'minimum_should_match': 1
        }
    })
    for fk in keywords:
        clause.append({'term': {'keywords': fk}})
        clause.append({'match_phrase': {"weibo_text": {"query": fk}}})
    return filter_clause


def add_filter_match(must_clause, filters, key, cond='must'):
    if key in filters:
        if filters[key]:
            clause = []
            must_clause.append({
                'bool': {cond: clause}
            })
            values = filters[key]
            if isinstance(values, str):
                values = values.split(' ')
            for fk in values:
                clause.append({'match': {key: {'query': fk, 'minimum_should_match': '20<100% 20<20'}}})
    return must_clause


def add_filter_clause_search2(filter_clause, filters, key, cond='must'):
    if key in filters:
        if filters[key]:
            clause = []
            filter_clause.append({
                'bool': {
                    cond: clause
                }
            })
            for fk in filters[key]:
                clause.append({'match_phrase': {key: {"query": fk}}})
    return filter_clause


def add_filter_clause(filter_clause, filters, key, cond='must'):
    if key in filters:
        if filters[key]:
            clause = []
            filter_clause.append({
                'bool': {
                    cond: clause
                }
            })
            for fk in filters[key]:
                clause.append({'term': {key: fk}})
    return filter_clause


def add_filter_clause2(filter_clause, filters, key, cond='must'):
    if key in filters:
        if filters[key]:
            clause = []
            filter_clause.append({
                'bool': {
                    cond: clause
                }
            })

            clause.append({'terms': {key: filters[key]}})
    return filter_clause


def add_filter_range_clause(filter_clause, filters, key):
    if key in filters:
        if filters[key]:
            clause = []
            filter_clause.append({
                'bool': {
                    'must': clause
                }
            })
            fk = filters[key]
            if not isinstance(fk, list) or len(fk) < 1:
                pass
            else:
                min_fk = fk[0]
                if len(fk) >= 2:
                    max_fk = fk[1]
                else:
                    max_fk = None
                if min_fk is not None and min_fk != 'null' and min_fk != '':
                    clause.append({'range': {key: {"gte": min_fk}}})
                if max_fk is not None and max_fk != 'null' and max_fk != '':
                    clause.append({'range': {key: {"lte": max_fk}}})
    return filter_clause


def get_post_sort(query, order, term, filters):
    if order == 'likes':
        query['sort'] = [
            {'likes': 'desc'},
            '_score'
        ]
    elif order == 'comments':
        query['sort'] = [
            {'comments': 'desc'},
            '_score'
        ]
    elif order == 'retweets':
        query['sort'] = [
            {'retweets': 'desc'},
            '_score'
        ]
    elif order == 'sum_engagement':
        query['sort'] = [
            {'sum_engagement': 'desc'},
            '_score'
        ]
    # elif order == 'relative':
    #     query['sort'] = [
    #         {'_score': 'desc'},
    #     ]
    #     if term == '':
    #         query['sort'] += [{'publish_timestamp': 'desc'}]
    else:
        query['sort'] = [
            {
                '_script': {
                    "type": "number",
                    "script": {
                        "lang": "painless",
                        "inline": "_score * Math.log(doc.publish_timestamp.value + 1.1) "
                                  "* Math.log(doc.category_weight.value + 1.0) "
                                  "* Math.log(doc.sum_engagement.value + 10.0)"
                    },
                    "order": "desc",
                },
            },
            '_score'
        ]
        if not term.strip():
            query['sort'] = [{'publish_timestamp': 'desc'}]

        if filters.get('category'):
            query['sort'] = [{'category_weight': 'desc'}] + query['sort']

    return query


def add_sentiment_filter_clause(filter_clause, filters, key):
    if key in filters:
        if filters[key] == [1]:
            clause = []
            filter_clause.append({
                'bool': {
                    'should': clause
                }
            })
            for fk in [1, 2]:
                clause.append({'term': {key: fk}})
        elif filters[key] == [5]:
            clause = []
            filter_clause.append({
                'bool': {
                    'should': clause
                }
            })
            for fk in [4, 5]:
                clause.append({'term': {key: fk}})
        else:
            clause = []
            filter_clause.append({
                'bool': {
                    'must': clause
                }
            })
            for fk in filters[key]:
                clause.append({'term': {key: fk}})
    return filter_clause


def get_post_filters(filter_clause, filters):
    filter_clause = add_filter_clause(filter_clause, filters, 'user_id', 'should')
    filter_clause = add_filter_clause(filter_clause, filters, 'is_retweet', 'should')
    filter_clause = add_filter_clause(filter_clause, filters, 'source')
    filter_clause = add_filter_clause_search2(filter_clause, filters, 'topics', 'should')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'publish_timestamp')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'likes')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'comments')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'retweets')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'sum_engagement')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'picture_num')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'video_num')
    filter_clause = add_filter_range_clause(filter_clause, filters, 'link_num')
    filter_clause = add_sentiment_filter_clause(filter_clause, filters, 'full_sentiment_category')

    filter_clause = add_filter_range_clause(filter_clause, filters, 'text_len')

    if filters.get('category'):
        filters['category'] = [category_smzdm_2_encode(c) for c in filters['category']]
        filters['category_weight'] = [CATEGORY_CUTOFF]
        filter_clause = add_filter_clause(filter_clause, filters, 'category', 'should')
        filter_clause = add_filter_range_clause(filter_clause, filters, 'category_weight')
    print(filter_clause)
    return filter_clause


def try_parsing_date(text):
    for fmt in ('%Y-%m-%d', '%d.%m.%Y', '%d/%m/%Y', '%Y%m%d', '%Y-%m-%d %H:%M:%S'):
        try:
            return datetime.datetime.strptime(text, fmt)
        except ValueError:
            pass
    raise ValueError('no valid date format found')
